package com.carsite.webapp.action;

import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationTrustResolver;
import org.acegisecurity.AuthenticationTrustResolverImpl;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.util.MessageResources;
import org.springframework.mail.SimpleMailMessage;

import com.carsite.Constants;
import com.carsite.model.Branch;
import com.carsite.model.Department;
import com.carsite.model.Role;
import com.carsite.model.User;
import com.carsite.service.BranchManager;
import com.carsite.service.DepartmentManager;
import com.carsite.service.LookupManager;
import com.carsite.service.MailEngine;
import com.carsite.service.RoleManager;
import com.carsite.service.UserExistsException;
import com.carsite.service.UserManager;
import com.carsite.webapp.form.UserForm;
import com.carsite.webapp.util.RequestUtil;

/**
 * Implementation of <strong>Action</strong> that interacts with the {@link
 * UserForm} and retrieves values. It interacts with the {@link UserManager} to
 * retrieve/persist values to the database.
 * 
 * <p>
 * <a href="UserAction.java.html"><i>View Source</i></a>
 * </p>
 * 
 * @author <a href="mailto:matt@raibledesigns.com">Matt Raible</a> Modified by
 *         <a href="mailto:dan@getrolling.com">Dan Kibler</a>
 * 
 * @struts.action name="userForm" path="/users" scope="request" validate="false"
 *                parameter="method" input="mainMenu"
 * 
 * @struts.action path="/userEditCustomer" scope="request" validate="false"
 *                parameter="method"
 * 
 * 
 * @struts.action name="userForm" path="/editUser" scope="request"
 *                validate="false" parameter="method" input="list"
 * @struts.action name="userForm" path="/editProfile" scope="request"
 *                validate="false" parameter="method" input="mainMenu"
 * @struts.action name="userForm" path="/saveUser" scope="request"
 *                validate="false" parameter="method" input="edit"
 * 
 * @struts.action-forward name="list" path="/WEB-INF/pages/userList.jsp"
 * @struts.action-forward name="edit" path="/WEB-INF/pages/userForm.jsp"
 * 
 * @struts.action-forward name="changePwdSucess" path="/index.html" redirect="true"
 * @struts.action-forward name="changePwdSucess_" path="/front/userchangePwdSucess.jsp"
 * @struts.action-forward name="changePwd" path="/front/userChangePwd.jsp"
 * @struts.action-forward name="customerList"
 *                        path="/WEB-INF/pages/customerList.jsp"
 * @struts.action-forward name="noRight" path="/front/front_noLogin.jsp"
 * 
 * 
 * 
 */
public final class UserAction extends BaseAction {

	public ActionForward add(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'add' method");
		}
		if (!this.check(request)) {
			return mapping.findForward("noRight");
		}
		User user = new User();
		user.addRole(new Role(Constants.USER_ROLE));
		UserForm userForm = (UserForm) convert(user);
		userForm.setEnabled(true);
		updateFormBean(mapping, request, userForm);

		checkForRememberMeLogin(request);

		BranchManager branchMgr = (BranchManager) getBean("branchManager");
		List topBranchList = branchMgr.getTopBranchs();
		request.setAttribute(Constants.BRANCH_LIST, topBranchList);

		// role
		LookupManager lookupMgr = (LookupManager) getBean("lookupManager");
		request
				.setAttribute(Constants.AVAILABLE_ROLES, lookupMgr
						.getAllRoles());

		return mapping.findForward("edit");
	}

	public ActionForward cancel(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'cancel' method");
		}

		if (!StringUtils.equals(request.getParameter("from"), "list")) {
			return mapping.findForward("mainMenu");
		} else {
			return mapping.findForward("viewUsers");
		}
	}

	public ActionForward delete(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'delete' method");
		}
		if (!this.check(request)) {
			return mapping.findForward("noRight");
		}
		// Extract attributes and parameters we will need
		ActionMessages messages = new ActionMessages();
		UserForm userForm = (UserForm) form;

		// Exceptions are caught by ActionExceptionHandler
		UserManager mgr = (UserManager) getBean("userManager");
		try {
			// mgr.removeUser(userForm.getId());
			mgr.removeAppUser(userForm.getId());
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
				"user.deleted", userForm.getFirstName()));

		saveMessages(request.getSession(), messages);

		// return a forward to searching users
		return mapping.findForward("viewUsers");
	}

	public ActionForward edit(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'edit' method");
		}
		if (!this.check(request)) {
			return mapping.findForward("noRight");
		}
		UserForm userForm = (UserForm) form;

		// if URL is "editProfile" - make sure it's the current user
		if (request.getRequestURI().indexOf("editProfile") > -1) {
			// reject if username passed in or "list" parameter passed in
			// someone that is trying this probably knows the AppFuse code
			// but it's a legitimate bug, so I'll fix it. ;-)
			if ((request.getParameter("username") != null)
					|| (request.getParameter("from") != null)) {
				response.sendError(HttpServletResponse.SC_FORBIDDEN);
				log.warn("User '" + request.getRemoteUser()
						+ "' is trying to edit user '"
						+ request.getParameter("username") + "'");

				return null;
			}
		}

		// Exceptions are caught by ActionExceptionHandler
		UserManager mgr = (UserManager) getBean("userManager");
		User user = null;

		if (userForm.getId() != null) {
			user = mgr.getUser(userForm.getId());
		} else {
			user = (User) this.convert(userForm);
		}

		BeanUtils.copyProperties(userForm, convert(user));// /?????
		userForm.setConfirmPassword(userForm.getPassword());

		// add company dept info to actionform

		if (user.getBranch() != null) {
			userForm.setBranchId(user.getBranch().getBranchId().toString());
			userForm.setBranchName(user.getBranch().getBranchName());
		}

		if (user.getDept() != null) {
			userForm.setDeptId(user.getDept().getDeptId().toString());
			userForm.setDeptName(user.getDept().getDeptName());
		}

		updateFormBean(mapping, request, userForm);

		checkForRememberMeLogin(request);

		// branch
		BranchManager branchMgr = (BranchManager) getBean("branchManager");
		List topBranchList = branchMgr.getTopBranchs();
		request.setAttribute(Constants.BRANCH_LIST, topBranchList);
		// role
		LookupManager lookupMgr = (LookupManager) getBean("lookupManager");
		request
				.setAttribute(Constants.AVAILABLE_ROLES, lookupMgr
						.getAllRoles());

		// return a forward to edit forward
		return mapping.findForward("edit");

	}

	public ActionForward changePwd(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		if (log.isDebugEnabled()) {
			log.debug("Entering 'changePwd' method");
		}
		ActionMessages messages = new ActionMessages();
		HttpSession session = request.getSession(false);
		User currentUser = (User) session
				.getAttribute("currentUser");
		if (currentUser == null) {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"user.noLogin"));
			saveErrors(session, messages);
			return mapping.findForward("noRight");
		}
		log.debug(currentUser.toString());
		// Extract attributes and parameters we will need

		UserForm userForm = (UserForm) form;
		try {
			if (userForm.getPassword()==null||userForm.getConfirmPassword()==null||!(userForm.getPassword().equals(userForm.getConfirmPassword()))) {
				messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
						"user.changePwd.pwdNotEqualsConfirm"));
				saveErrors(request.getSession(false), messages);
				return mapping.findForward("changePwd");
			}
		} catch (RuntimeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		String oldPassword = request.getParameter("oldPassword");
		if (oldPassword == null) {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"user.password.null"));
			saveErrors(request.getSession(false), messages);
			return mapping.findForward("changePwd");
		}

		UserManager mgr = (UserManager) getBean("userManager");
		User user = mgr.getUser(currentUser.getId()
				.toString());
		if (!oldPassword.equals(user.getPassword())) {
			messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
					"user.password.old.error"));
			saveErrors(request.getSession(false), messages);
			return mapping.findForward("changePwd");
		}
		user.setPassword(userForm.getPassword());
		mgr.saveUser(user);

		// add success messages
		messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
				"userForm.password.updated"));
		saveMessages(request, messages);
		String msg = "1";////???
		request.setAttribute("msg", msg);///????
		return mapping.findForward("changePwdSucess_");
	}
    
    
    public ActionForward save(ActionMapping mapping, ActionForm form,
                              HttpServletRequest request,
                              HttpServletResponse response)
    throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Entering 'save' method");
        }
        if(!this.check(request)){
        	return mapping.findForward("noRight");
        }
        // run validation rules on this form
        // See https://appfuse.dev.java.net/issues/show_bug.cgi?id=128
        ActionMessages errors = form.validate(mapping, request);

        if (!errors.isEmpty()) {
            saveErrors(request, errors);
            return mapping.findForward("edit");
        }

        // Extract attributes and parameters we will need
        ActionMessages messages = new ActionMessages();
        UserForm userForm = (UserForm) form;
        System.out.println(userForm.getPassword());
        System.out.println(userForm.getConfirmPassword());
        User user = new User();

        // Exceptions are caught by ActionExceptionHandler
        // all we need to persist is the parent object
        BeanUtils.copyProperties(user, userForm);

        Boolean encrypt = (Boolean) getConfiguration().get(Constants.ENCRYPT_PASSWORD);

        if (StringUtils.equals(request.getParameter("encryptPass"), "true") 
                && (encrypt != null && encrypt.booleanValue())) {
            String algorithm = (String) getConfiguration().get(Constants.ENC_ALGORITHM);

            if (algorithm == null) { // should only happen for test case
                log.debug("assuming testcase, setting algorithm to 'SHA'");
                algorithm = "SHA";
            }
            System.out.println(user.getPassword());
            user.setPassword(user.getPassword());
            System.out.println(user.getPassword());
        }

        UserManager mgr = (UserManager) getBean("userManager");
        RoleManager roleMgr = (RoleManager) getBean("roleManager");
        String[] userRoles = request.getParameterValues("userRoles");

        for (int i = 0; userRoles != null &&  i < userRoles.length; i++) {
            String roleName = userRoles[i];
            user.addRole(roleMgr.getRole(roleName));
        }
        
        // save dept company info
        
        if(userForm.getBranchId()!=null && ! userForm.getBranchId().equals("")){
        	
        	 BranchManager branchMgr = (BranchManager) getBean("branchManager");
             
        	 Branch branch = branchMgr.getBranch(userForm.getBranchId());
        	
        	user.setBranch(branch);
        }
        
        if(userForm.getDeptId()!=null && ! userForm.getDeptId().equals("") ){
        	DepartmentManager deptMgr = (DepartmentManager) getBean("departmentManager");
            Department department = deptMgr.getDepartment(userForm.getDeptId());
        	user.setDept(department);
        }
        
        
        
        
        try {
            mgr.saveUser(user);
        } catch (UserExistsException e) {
            log.warn(e.getMessage());
            errors.add(ActionMessages.GLOBAL_MESSAGE,
                       new ActionMessage("errors.existing.user",
                                         userForm.getUsername(),
                                         userForm.getEmail()));
            saveErrors(request, errors);

            BeanUtils.copyProperties(userForm, convert(user));
            userForm.setConfirmPassword(userForm.getPassword());
            // reset the version # to what was passed in
            userForm.setVersion(request.getParameter("version"));
            updateFormBean(mapping, request, userForm); 
            
            return mapping.findForward("edit");
        }
         
        BeanUtils.copyProperties(userForm, convert(user));
        userForm.setConfirmPassword(userForm.getPassword());
        updateFormBean(mapping, request, userForm);
        
       
        // add success messages
        if ("".equals(request.getParameter("version"))) {
            messages.add(ActionMessages.GLOBAL_MESSAGE,
                         new ActionMessage("user.added", user.getFullName()));
            saveMessages(request.getSession(), messages);
            sendNewUserEmail(request, userForm);
        } else {
            messages.add(ActionMessages.GLOBAL_MESSAGE,
                         new ActionMessage("user.updated.byAdmin",
                                           user.getFullName()));
            saveMessages(request, messages);
        }
        
        BranchManager branchMgr = (BranchManager) getBean("branchManager");
        List topBranchList = branchMgr.getTopBranchs();
        request.setAttribute(Constants.BRANCH_LIST,topBranchList);
        
        //role
        LookupManager lookupMgr = (LookupManager) getBean("lookupManager");
        request.setAttribute(Constants.AVAILABLE_ROLES, lookupMgr.getAllRoles());
        
        return add(mapping, form, request, response);
        //return mapping.findForward("edit");
       
    }

    public ActionForward search(ActionMapping mapping, ActionForm form,
                                HttpServletRequest request,
                                HttpServletResponse response)
    throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Entering 'search' method");
        }
        if(!this.check(request)){
        	return mapping.findForward("noRight");
        }
        UserForm userForm = (UserForm) form;

        // Exceptions are caught by ActionExceptionHandler
        UserManager mgr = (UserManager) getBean("userManager");
        User user = (User) convert(userForm);
       //User user=new User();
        
        	//List users = mgr.getUsers(user);
        	try {
				//List users = mgr.getUsers(user);
				List users=mgr.getAppUsers(user);
				request.setAttribute(Constants.USER_LIST, users);
			} catch (RuntimeException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
		
        // return a forward to the user list definition
        return mapping.findForward("list");
    }
    
    public ActionForward unspecified(ActionMapping mapping, ActionForm form,
                                     HttpServletRequest request,
                                     HttpServletResponse response)
    throws Exception {
        
        return search(mapping, form, request, response);
    }

    private void sendNewUserEmail(HttpServletRequest request, UserForm userForm)
    throws Exception {
        MessageResources resources = getResources(request);

        // Send user an e-mail
        if (log.isDebugEnabled()) {
            log.debug("Sending user '" + userForm.getUsername() +
                      "' an account information e-mail");
        }

        SimpleMailMessage message = (SimpleMailMessage) getBean("mailMessage");
        message.setTo(userForm.getFullName() + "<" + userForm.getEmail() + ">");

        StringBuffer msg = new StringBuffer();
        msg.append(resources.getMessage("newuser.email.message",
                                        userForm.getFullName()));
        msg.append("\n\n" + resources.getMessage("userForm.username"));
        msg.append(": " + userForm.getUsername() + "\n");
        msg.append(resources.getMessage("userForm.password") + ": ");
        msg.append(userForm.getPassword());
        msg.append("\n\nLogin at: " + RequestUtil.getAppURL(request));
        message.setText(msg.toString());

        message.setSubject(resources.getMessage("signup.email.subject"));

        MailEngine engine = (MailEngine) getBean("mailEngine");
        engine.send(message);
    }

    private void checkForRememberMeLogin(HttpServletRequest request) {
		// if user logged in with remember me, display a warning that they can't change passwords
		log.debug("checking for remember me login...");

		AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl();
		SecurityContext ctx = SecurityContextHolder.getContext();

		if (ctx != null) {
			Authentication auth = ctx.getAuthentication();

			if (resolver.isRememberMe(auth)) {
				request.getSession().setAttribute("cookieLogin", "true");

				// add warning message
				ActionMessages messages = new ActionMessages();
				messages.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage(
						"userProfile.cookieLogin"));
				saveMessages(request, messages);
			}
		}
	}
    public boolean check(HttpServletRequest request){
		 HttpSession session=request.getSession();
		 if(session==null){
			 return false;
		 }else{
			 User currentUser=(User)session.getAttribute("currentUser");
			 if(currentUser==null){
				 return false;
			 }else{
				 Set roles=currentUser.getRoles();
				 Iterator rolesIt=(Iterator)roles.iterator();
				 while(rolesIt.hasNext()){
					 Role role=(Role)rolesIt.next();
					 System.out.println(role.getName());
					 if(role.getName().equals("admin")){
						 return true;
					 }
				 }
				 return false;
			 }
		 }
		
	 }
    
}
